package com.ants.boot.core.security.filter;

import com.alibaba.fastjson.JSONObject;
import com.ants.boot.core.security.token.CustomAuthenticationToken;
import com.ants.boot.core.security.token.PhoneAuthenticationToken;
import com.ants.boot.utils.RedisUtils;
import org.springframework.security.authentication.AuthenticationServiceException;
import org.springframework.security.core.Authentication;
import org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter;
import org.springframework.security.web.util.matcher.AntPathRequestMatcher;
import org.springframework.util.StreamUtils;
import org.springframework.util.StringUtils;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.nio.charset.Charset;

/**
 * @author 蚂蚁会花呗
 * @date 2022/2/23 11:39
 * 认证过滤器，该过滤器的作用是从请求中获取用户的身份认证信息，并将其传递给AuthenticationManager进行身份验证
 * 不同认证方式可以设置多个过滤器
 * 这里普通登录和手机号验证码登录我使用了统一的认证过滤器，登录接口都是/ants/login，通过传参不同进入到各自的认证实现
 * 一、普通方式账号密码登录：
 * 获取验证码：http://localhost:8087/ants-boot-local/ants/captcha
 * 登录：http://localhost:8087/ants-boot-local/ants/login
 * 登录传参：
 * {
 *     "username":"wangwq1",
 *     "password": "123456",
 *     "key":"932369a6-6711-4366-9777-f65081c76f54",
 *     "code":"mytn"
 * }
 * 二、手机验证码登录
 * 获取手机验证码：http://localhost:8087/ants-boot-local/ants/send_captcha
 * 登录：http://localhost:8087/ants-boot-local/ants/login
 * 登录传参：
 * {
 *     "username":"18698589625",
 *     "password": "134636",
 *     "type":"code"
 * }
 *
 */
public class LoginAuthenticationFilter extends AbstractAuthenticationProcessingFilter {

    /**
     * 设置request attribute 登录账户
     */
    private static final String REQUEST_LOGIN_USER_ATTRIBUTE = "LOGIN_USER";

    private RedisUtils redisUtils;

    public LoginAuthenticationFilter(RedisUtils redisUtils) {
        super(new AntPathRequestMatcher("/ants/login", "POST"));
        this.redisUtils = redisUtils;
    }

    @Override
    public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response) throws IOException {
        //从请求中获取用户名，密码
        Authentication authRequest = null;
        String body = StreamUtils.copyToString(request.getInputStream(), Charset.forName("UTF-8"));
        String username, password, code,key;
        if(StringUtils.hasText(body)) {
            JSONObject jsonElement = (JSONObject) JSONObject.parse(body);
            username = jsonElement.getString("username") == null ? "" : jsonElement.getString("username").trim();
            password = jsonElement.getString("password") == null ? "" : jsonElement.getString("password").trim();
            //短信验证码登录
            if (jsonElement.containsKey("type") && jsonElement.get("type").toString().equals("code")){
                authRequest = new PhoneAuthenticationToken(username, password);
            }else{
                //常规登录
                code = jsonElement.getString("code") == null ? "" : jsonElement.getString("code").trim();
                key = jsonElement.getString("key") == null ? "" : jsonElement.getString("key").trim();
                request.setAttribute(REQUEST_LOGIN_USER_ATTRIBUTE,username);
                if (redisUtils.get(key) == null || !redisUtils.get(key).toString().equalsIgnoreCase(code)) {
                    request.removeAttribute(REQUEST_LOGIN_USER_ATTRIBUTE);
                    throw new AuthenticationServiceException("验证码不正确");
                }
                //封装到token中提交
                authRequest = new CustomAuthenticationToken(
                        username,password);
            }
        }
        return getAuthenticationManager().authenticate(authRequest);
    }
}
